#define _GLIBCXX17_DEPRECATED_SUGGEST(ALT) _GLIBCXX_DEPRECATED_SUGGEST(ALT)
#pragma once
#include <thread>
#include <vector>
#include <functional>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <future>
#include <stdexcept>

class ThreadPool
{
public:
    ThreadPool(size_t threads)
        : stop_(false)
    {
        for (size_t i = 0 ; i < threads; ++i)
        {
            workers_.emplace_back([this](){
                while(1)
                {
                    std::function<void()> task;
                    {
                        // 从任务队列中获取任务
                        std::unique_lock<std::mutex> lock(queue_mutex_);
                        cond_.wait(lock, [this](){
                            return stop_ || !tasks_.empty();
                        });
                        if (stop_ && tasks_.empty())
                            return;
                        task = std::move(tasks_.front());
                        tasks_.pop();
                    }
                    // 执行任务
                    task();
                }
            });
        }
    }

    /**
     * @param f 是一个可调用对象
     * @param args 是可调用对象f接收的参数
     * @return std::future<可调用对象f的返回值类型>
     */
    template<typename F, typename... Args>
    auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type>
    {
        using result_type = typename std::result_of<F(Args...)>::type;
        // 创建一个打包任务，将有参调用打包成无参调用
        // std::package_task内部包含了一个promise对象，可以通过task->get_future获取关联的std::future
        auto task = std::make_shared<std::packaged_task<result_type()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
        auto res = task->get_future();
        {
            std::unique_lock<std::mutex> lock(queue_mutex_);
            if (stop_) 
                throw std::runtime_error("enqueue on stopped ThreadPool");
            tasks_.emplace([task](){
                // 使用lambda表达式封装成无返回值调用
                (*task)();
            });
        }
        // 有新任务添加进行，通知一个线程来进行处理
        cond_.notify_one();
        return res;
    }

    ~ThreadPool()
    {
        // 原子变量不需要特意同步
        stop_ = true;
        cond_.notify_all();
        for (auto& worker : workers_)
        {
            worker.join();
        }
    }


private:
    std::vector<std::thread> workers_; // 任务执行线程
    std::queue<std::function<void()>> tasks_; // 任务队列
    std::mutex queue_mutex_; // 任务队列的互斥量
    std::condition_variable cond_;
    std::atomic<bool> stop_;
};